package com.google.code.msgbooster.batch.detector;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import com.google.code.msgbooster.batch.Meta;
import com.google.code.msgbooster.model.extension.Guide;

public abstract class Core extends Meta {

	private int reconnectTimes = 0;

	protected abstract List<Clip> resolve(InputStream inputStream, Guide guide)
			throws Exception;

	protected abstract boolean isReconnect(Exception exception, boolean result);

	private InputStream connect(Guide guide) throws Exception {
		return ((HttpURLConnection) (new URL(guide.getResource().getValue())).openConnection())
				.getInputStream();
	}

	protected Result createResult(boolean success, boolean reconnect,
			String cause, List<Clip> clips) {
		Result result = new Result();
		result.setReconnect(reconnect);
		result.setSuccess(success);
		result.setCause(cause);
		result.setClips(clips);
		return result;
	}

	private final Result execute(Guide guide) {
		List<Clip> emptyClipList = new ArrayList<Clip>();
		Result result = createResult(true, false, null, emptyClipList);
		try {
			InputStream inputStream = connect(guide);
			info(getProperty("msgbooster.batch.collector.core.get.success"));
			try {
				result = createResult(true, false, null, resolve(inputStream, guide));
				info(getProperty("msgbooster.batch.collector.core.resolve.success"));
			} catch (Exception exception) {
				result = createResult(false, isReconnect(exception, false), exception.getMessage(), emptyClipList);
				warn(getProperty("msgbooster.batch.collector.core.resolve.fail"), exception);
			}
		} catch (Exception exception) {
			if (SocketTimeoutException.class.isInstance(exception)) {
				result = createResult(false, true, exception.getMessage(), emptyClipList);
			} else {
				result = createResult(false, false, exception.getMessage(), emptyClipList);
			}
			warn(getProperty("msgbooster.batch.collector.core.get.fail"), exception);
		}
		return result;
	}

	public final Result get(Guide guide) {
		Result result = execute(guide);
		if (!result.isSuccess())
			if (result.isReconnect())
				if (reconnectTimes++ < getRetryTimes())
					result = get(guide);

		return result;
	}

}
